package com.cbs.android.component.application;

import android.app.ActivityManager;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.multidex.MultiDex;

import com.cbs.android.component.application.activity.CBSLoadResActivity;
import com.cbs.android.component.log.L;

import org.apache.commons.lang3.StringUtils;

import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

/**
 * Created by broche on 9/28/15.
 */
public class CBSApplication extends Application {
    private static final String KEY_DEX2_SHA1 = "dex2-SHA1-Digest";
    private static final String TAG = CBSApplication.class.getName();

    protected boolean multiDexEnabled() {
        return false;
    }

    public void onAppCreate() {

    }

    @Override
    public final void onCreate() {
        super.onCreate();

        if (multiDexEnabled()) {
            if (quickStart()) {
                return;
            }
        }
        onAppCreate();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        if (multiDexEnabled()) {
            L.d(TAG, "App attachBaseContext");
            if (!quickStart() && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // >= 5.0 system optimize dex automaticlly
                if (needWait(base)) {
                    waitForDexopt(base);
                }
                MultiDex.install(this);
            } else {
                // do nothing
            }
        }
    }

    private boolean quickStart() {
        if (StringUtils.contains(getCurProcessName(this), ":mini")) {
            L.d(TAG, ":mini start!");
            return true;
        } else {
            return false;
        }
    }

    private boolean needWait(Context context) {
        String flag = get2ndDexSHA1(context);
        L.d(TAG, "dex2-sha1" + flag);
        SharedPreferences sharedPreferences = context.getSharedPreferences(getPackageInfo(context).versionName, MODE_MULTI_PROCESS);
        String saveValue = sharedPreferences.getString(KEY_DEX2_SHA1, "");
        return !StringUtils.equals(flag, saveValue);
    }

    private String get2ndDexSHA1(Context context) {
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        String source = applicationInfo.sourceDir;
        try {
            JarFile jarFile = new JarFile(source);
            java.util.jar.Manifest manifest = jarFile.getManifest();
            Map<String, Attributes> map = manifest.getEntries();
            Attributes attributes = map.get("classes2.dex");
            if (attributes != null) {
                return attributes.getValue("SHA1-Digest");
            } else {
                return null;
            }
        } catch (Exception e) {
            L.d(TAG, "", e);
        }
        return null;
    }

    private static String getCurProcessName(Context context) {
        try {
            int pid = android.os.Process.myPid();
            ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            for (ActivityManager.RunningAppProcessInfo appProcessInfo : activityManager.getRunningAppProcesses()) {
                if (appProcessInfo.pid == pid) {
                    return appProcessInfo.processName;
                }
            }
        } catch (Exception e) {
            L.d(TAG, "", e);
        }
        return null;
    }

    private void waitForDexopt(Context base) {
        Intent intent = new Intent();
        ComponentName componentName = new ComponentName(getPackageInfo(base).packageName, CBSLoadResActivity.class.getName());
        intent.setComponent(componentName);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        base.startActivity(intent);
        long startWait = System.currentTimeMillis();
        long waitTime = 10 * 1000;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
            waitTime = 20 * 1000;
        }
        while (needWait(base)) {
            try {
                long nowWait = System.currentTimeMillis() - startWait;
                L.d(TAG, "wait ms: " + nowWait);
                if (nowWait >= waitTime) {
                    return;
                }
                Thread.sleep(200);
            } catch (InterruptedException e) {
                L.d(TAG, "", e);
            }
        }
    }

    private PackageInfo getPackageInfo(Context context) {
        PackageManager packageManager = context.getPackageManager();
        try {
            return packageManager.getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            L.d(TAG, "", e);
        }
        return new PackageInfo();
    }

    public void installFinish(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(getPackageInfo(context).versionName, MODE_MULTI_PROCESS);
        sharedPreferences.edit().putString(KEY_DEX2_SHA1, get2ndDexSHA1(context)).apply();
    }
}
